package top.infopub.mgr.util;


import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import top.infopub.exception.ServiceException;
import top.infopub.mgr.exception.ExtNotAllowedException;
import top.infopub.mgr.exception.SizeOutOfLimitException;
import top.infopub.tdp.util.GrpParaUtil;
import top.infopub.util.IdFactory;

import com.google.common.collect.Maps;


/**
 * 文件上传/下载 工具类 
 * @author Awoke
 * @version 2019年12月31日
 * @see FileHelper
 * @since
 */
public final class FileHelper {

    private static Logger log = LoggerFactory.getLogger(FileHelper.class);

    public static Map<String, Tip> keyTip = Maps.newHashMap();

    static {
        keyTip.put("zip", new FileHelper.Tip("application/zip", 100));
        keyTip.put("rar", new FileHelper.Tip("application/x-rar-compressed", 100));
        keyTip.put("jpg", new FileHelper.Tip("image/jpeg", 20));
        keyTip.put("jpeg", new FileHelper.Tip("image/jpeg", 20));
        keyTip.put("png", new FileHelper.Tip("image/jpeg", 20));
        keyTip.put("pdf", new FileHelper.Tip("application/pdf", 100));
        keyTip.put("xls", new FileHelper.Tip("application/vnd.ms-excel", 40));
        keyTip.put("xlsx", new FileHelper.Tip(
            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", 40));
        keyTip.put("doc", new FileHelper.Tip("application/msword", 100));
        keyTip.put("docx", new FileHelper.Tip(
            "application/vnd.openxmlformats-officedocument.wordprocessingml.document", 100));
        keyTip.put("ppt", new FileHelper.Tip("application/vnd.ms-powerpoint", 40));
        keyTip.put("pptx", new FileHelper.Tip(
            "application/vnd.openxmlformats-officedocument.presentationml.presentation", 40));
    }

    /**
     * 上传文件到服务器
     * @param multiFile  文件采用springmvc上传而来
     * @param baseFolder 文件保存的目录 前后不需要/
     * @return  返回保存后的文件完整[虚拟]路径
     * @see
     */
    public static String upload(MultipartFile multiFile, String baseFolder) {
        if (baseFolder.startsWith("/")) {
            baseFolder = baseFolder.substring(1);
        }
        if (!baseFolder.endsWith("/")) {
            baseFolder = baseFolder + "/";
        }
        // 文件的真实保存地址 （增加年月日文件夹）
        String fullFolder = GrpParaUtil.getValue("A00010054", "upload_file_docBase") + "/" + baseFolder
                     + DateFormatUtils.format(new Date(), "yyyyMMdd") + "/";

        // 文件后缀
        String ext = FilenameUtils.getExtension(multiFile.getOriginalFilename());
        if (StringUtils.isNotBlank(ext)) {
            ext = ext.toLowerCase();
        }
        else {
            throw new ExtNotAllowedException("不支持此格式的文件上传，后缀无效");
        }
        if (!keyTip.containsKey(ext)) {
            throw new ExtNotAllowedException("不支持此格式的文件上传：" + ext);
        }
        // 判断大小
        long size = multiFile.getSize();
        Tip tip = keyTip.get(ext);
        if (size > tip.getUploadMaxSizeByte()) {
            throw new SizeOutOfLimitException(tip.getUploadSizeLimit());
        }
        // 文件名
        String uuidName = IdFactory.getUUIDSerialNumber() + "." + ext;
        try {
            mkdirs(fullFolder);
            FileUtils.writeByteArrayToFile(new File(fullFolder + uuidName), multiFile.getBytes());
            // 返回对应的虚拟路径 含文件名
            return GrpParaUtil.getValue("A00010054", "upload_file_path") + "/" + baseFolder
                   + DateFormatUtils.format(new Date(), "yyyyMMdd") + "/" + uuidName;
        }
        catch (Exception e) {
            throw new ServiceException("文件上传异常，请重试");
        }
    }

    /**
     * 输出本地文件到浏览器流下载，如果不存在对应的文件 抛出异常
     * @param filePath：下载文件的本地路径 含文件名
     * @return
     */
    public static void download(String filePath, HttpServletResponse response) {
        String ext = FilenameUtils.getExtension(filePath).toLowerCase();
        String fileName = FilenameUtils.getName(filePath);
        String mimeType = FileHelper.keyTip.get(ext).getMimeType();
        InputStream fis = null;
        OutputStream fos = null;
        try {
            // 开始下载流文件 
            response.reset(); // 设置response的Header
            response.setContentType(mimeType + ";charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename="
                                                      + new String((fileName).getBytes(),
                                                          "iso-8859-1"));
            response.setContentLength((int)new File(filePath).length());

            fis = new BufferedInputStream(new FileInputStream(filePath));
            fos = new BufferedOutputStream(response.getOutputStream());
            byte[] buffer = new byte[1024 * 8];
            int read = -1;
            while (-1 != (read = fis.read(buffer, 0, buffer.length))) {
                fos.write(buffer, 0, read);
            }
            fos.flush();
            response.flushBuffer();
            log.debug("downloadLocal successfully, filePath={} ", filePath);
        }
        catch (Exception e) {
            log.error("downloadLocal error", e);
        }
        finally {
            IOUtils.closeQuietly(fis);
            IOUtils.closeQuietly(fos);
        }
    }

    /**
     * 如果本地目录不存在则创建
     * @param path
     */
    private static void mkdirs(String path) {
        try {
            File f = new File(path);
            String fs = f.getParent();
            f = new File(fs);
            if (!f.exists()) {
                f.mkdirs();
            }
        }
        catch (Exception e) {
            log.error("--{}-- mkLocalDirs error", path, e);
        }
    }

    static class Tip {

        /**
         * mimeType
         */
        private String mimeType;

        /**
         * 最大限制 单位MB
         */
        private int uploadMaxSizeMb;

        /**
         * 最大限制 单位B
         */
        private long uploadMaxSizeByte;

        /**
         * 文件过大 提示
         */
        private String uploadSizeLimit;

        public Tip() {
            super();
        }

        /**
         * @param mimeType   mimeType
         * @param uploadMaxSizeMb  最大限制 单位MB
         */
        public Tip(String mimeType, int uploadMaxSizeMb) {
            super();
            this.mimeType = mimeType;
            this.uploadMaxSizeMb = uploadMaxSizeMb;
            this.uploadMaxSizeByte = uploadMaxSizeMb * 1024L * 1024L;
            this.uploadSizeLimit = "文件不能超过" + uploadMaxSizeMb + "M";
        }

        public String getMimeType() {
            return mimeType;
        }

        public void setMimeType(String mimeType) {
            this.mimeType = mimeType;
        }

        public int getUploadMaxSizeMb() {
            return uploadMaxSizeMb;
        }

        public void setUploadMaxSizeMb(int uploadMaxSizeMb) {
            this.uploadMaxSizeMb = uploadMaxSizeMb;
        }

        public long getUploadMaxSizeByte() {
            return uploadMaxSizeByte;
        }

        public void setUploadMaxSizeByte(long uploadMaxSizeByte) {
            this.uploadMaxSizeByte = uploadMaxSizeByte;
        }

        public String getUploadSizeLimit() {
            return uploadSizeLimit;
        }

        public void setUploadSizeLimit(String uploadSizeLimit) {
            this.uploadSizeLimit = uploadSizeLimit;
        }
    }

}
